from rest_framework.views import APIView
from rest_framework.response import Response
from rest_framework import status
from .models import PersonalInfo
from .resume_serializer import PersonalInfoSerializer
from services.message_audit_factory import MessageAuditFactory


# 1. 仅负责「创建简历」（POST请求）
class ResumeCreateAPIView(APIView):
    """
    简历创建接口（无需登录）
    - POST：提交个人信息+关联经历，验证后入库
    """
    permission_classes = []  # 公开访问，无需登录

    def post(self, request):
        try:
            # 初始化序列化器，校验前端提交的数据
            serializer = PersonalInfoSerializer(data=request.data)
            
            # 先进行验证，不直接抛出异常，以便可以格式化错误信息
            if not serializer.is_valid():
                # 格式化错误信息，使其更易读
                errors = serializer.errors
                formatted_errors = self._format_validation_errors(errors)
                return Response(
                    {
                        "error": "数据验证失败",
                        "details": formatted_errors,
                        "raw_errors": errors  # 保留原始错误信息用于调试
                    },
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 违规词审核
            audit_result = audit_resume_payload(validated_data=serializer.validated_data)
            if not audit_result["passed"]:
                return Response(
                    {
                        "error": "简历内容包含违规词",
                        "details": audit_result
                    },
                    status=status.HTTP_400_BAD_REQUEST
                )
            
            # 验证通过，保存数据
            serializer.save()  # 调用序列化器create方法，创建主表+关联表数据

            
            # 验证通过，保存数据
            serializer.save()  # 调用序列化器create方法，创建主表+关联表数据

            # 生成响应头（符合REST规范，返回新资源ID）
            headers = self.get_success_headers(serializer.data)
            return Response(
                serializer.data,  # 返回创建成功的完整数据（含自动生成的ID）
                status=status.HTTP_201_CREATED,
                headers=headers
            )
        except Exception as e:
            # 捕获其他异常（如数据库错误）
            import traceback
            error_detail = traceback.format_exc()
            print("=" * 80)
            print("创建简历时发生异常：")
            print(error_detail)
            print("=" * 80)
            return Response(
                {
                    "error": "创建简历时发生错误",
                    "detail": str(e),
                    "message": "请检查数据格式和服务器日志"
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )
    
    def _format_validation_errors(self, errors):
        """
        格式化验证错误信息，使其更易读
        :param errors: DRF返回的错误字典
        :return: 格式化后的错误信息列表
        """
        formatted = []
        
        for field, error_list in errors.items():
            # 处理嵌套序列化器的错误
            nested_fields = [
                'work_experiences',
                'education_experiences',
                'project_experiences'
            ]
            if field in nested_fields:
                if isinstance(error_list, list):
                    # 遍历每条经历的错误
                    for idx, item_errors in enumerate(error_list):
                        if isinstance(item_errors, dict):
                            # 每条经历可能有多个字段错误
                            item_error_msgs = []
                            for error_field, error_msgs in item_errors.items():
                                if isinstance(error_msgs, list):
                                    msg = f"{error_field}: {', '.join(error_msgs)}"
                                    item_error_msgs.append(msg)
                                else:
                                    msg = f"{error_field}: {error_msgs}"
                                    item_error_msgs.append(msg)
                            if item_error_msgs:
                                error_str = '; '.join(item_error_msgs)
                                formatted.append(f"{field}[{idx + 1}]: {error_str}")
                        elif isinstance(item_errors, list):
                            # 如果错误是列表格式
                            error_str = ', '.join(item_errors)
                            formatted.append(f"{field}[{idx + 1}]: {error_str}")
                elif isinstance(error_list, dict):
                    # 如果是字典格式的错误
                    for error_key, error_value in error_list.items():
                        formatted.append(f"{field}.{error_key}: {error_value}")
                else:
                    formatted.append(f"{field}: {error_list}")
            else:
                # 处理普通字段的错误
                if isinstance(error_list, list):
                    formatted.append(f"{field}: {', '.join(error_list)}")
                else:
                    formatted.append(f"{field}: {error_list}")
        
        return formatted

    # 辅助方法：生成Location响应头（资源定位）
    def get_success_headers(self, data):
        try:
            return {'Location': str(data['id'])}  # Location头携带简历ID，方便前端跳转
        except (TypeError, KeyError):
            return {}


# 2. 负责「查看列表/详情」+「在线编辑（部分更新）」
class ResumeDetailAPIView(APIView):
    """
    简历核心操作接口（无需登录）
    - GET：查询所有简历列表（无resume_id）/ 单个简历详情（有resume_id）
    - PATCH：部分更新简历（支持在线编辑，仅提交修改字段）
    """
    permission_classes = []  # 公开访问，无需登录

    # 查看功能（列表/详情）
    def get(self, request, resume_id=None):
        # 场景1：无resume_id → 返回所有简历列表（预加载关联经历，优化性能）
        if resume_id is None:
            resumes = PersonalInfo.objects.all().prefetch_related(
                'work_experiences',
                'project_experiences',
                'education_experiences'
            )
            serializer = PersonalInfoSerializer(resumes, many=True)
            return Response(serializer.data, status=status.HTTP_200_OK)

        # 场景2：有resume_id → 返回单个简历详情
        try:
            resume = PersonalInfo.objects.prefetch_related(
                'work_experiences',
                'project_experiences',
                'education_experiences'
            ).get(id=resume_id)
            serializer = PersonalInfoSerializer(resume)
            return Response(serializer.data, status=status.HTTP_200_OK)
        except PersonalInfo.DoesNotExist:
            return Response(
                {"error": f"未找到 ID为{resume_id}的简历（personal_info.id 不存在）"},
                status=status.HTTP_404_NOT_FOUND
            )

    def _update_resume(self, request, resume_id, partial=True):
        """
        更新简历的通用方法（被patch和post方法调用）
        :param request: HTTP请求对象
        :param resume_id: 简历ID
        :param partial: 是否部分更新（True=PATCH，False=POST完整更新）
        :return: Response对象
        """
        try:
            # 1. 查询要修改的简历（主表）
            resume = PersonalInfo.objects.prefetch_related(
                'work_experiences',
                'project_experiences',
                'education_experiences'
            ).get(id=resume_id)

            # 2. 初始化序列化器（instance=要修改的对象，data=前端提交的修改数据，partial=是否部分更新）
            serializer = PersonalInfoSerializer(
                instance=resume,
                data=request.data,
                partial=partial  # PATCH为True（部分更新），POST为False（完整更新）
            )

            # 3. 数据校验（失败则自动返回400+错误信息）
            serializer.is_valid(raise_exception=True)

            # 违规词审核（以更新后的最终数据为准）
            audit_result = audit_resume_payload(
                instance=resume,
                validated_data=serializer.validated_data
            )
            if not audit_result["passed"]:
                return Response(
                    {
                        "error": "简历内容包含违规词，更新被拒绝",
                        "details": audit_result
                    },
                    status=status.HTTP_400_BAD_REQUEST
                )

            # 4. 保存修改（调用序列化器的update方法，处理主表+关联表更新）
            serializer.save()

            # 5. 返回修改后的完整数据（前端刷新展示）
            return Response(serializer.data, status=status.HTTP_200_OK)
        except PersonalInfo.DoesNotExist:
            return Response(
                {"error": f"未找到 ID为{resume_id}的简历（无法修改）"},
                status=status.HTTP_404_NOT_FOUND
            )
        except AttributeError as e:
            # 捕获属性错误，返回友好的错误信息
            return Response(
                {
                    "error": "更新简历时发生属性错误",
                    "detail": str(e),
                    "message": "请检查提交的数据格式是否正确，确保所有必需的字段都已提供"
                },
                status=status.HTTP_400_BAD_REQUEST
            )
        except Exception as e:
            # 捕获其他所有异常，返回通用错误信息
            return Response(
                {
                    "error": "更新简历时发生错误",
                    "detail": str(e),
                    "message": "请检查数据格式和服务器日志"
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )

    # 在线编辑核心：部分更新（PATCH请求，支持修改任意字段）
    def patch(self, request, resume_id):
        """
        部分更新简历（在线编辑功能依赖）
        - 支持修改基本信息、新增/编辑/删除关联经历
        - 仅需提交修改的字段，无需传递所有必填项
        """
        return self._update_resume(request, resume_id, partial=True)

    # 兼容前端使用POST方法更新（完整更新）
    def post(self, request, resume_id):
        """
        完整更新简历（兼容前端使用POST方法）
        - 支持修改基本信息、新增/编辑/删除关联经历
        - 建议使用PATCH进行部分更新，POST用于完整更新
        """
        return self._update_resume(request, resume_id, partial=False)

    # 删除简历
    def delete(self, request, resume_id):
        """
        删除简历（包括所有关联的经历数据）
        - DELETE：删除指定ID的简历
        """
        try:
            # 查询要删除的简历
            resume = PersonalInfo.objects.get(id=resume_id)
            
            # 删除简历（关联的经历会自动级联删除，因为外键设置了on_delete=models.CASCADE）
            resume.delete()
            
            return Response(
                {"message": f"简历 ID={resume_id} 已成功删除"},
                status=status.HTTP_200_OK
            )
        except PersonalInfo.DoesNotExist:
            return Response(
                {"error": f"未找到 ID为{resume_id}的简历（无法删除）"},
                status=status.HTTP_404_NOT_FOUND
            )
        except Exception as e:
            return Response(
                {
                    "error": "删除简历时发生错误",
                    "detail": str(e)
                },
                status=status.HTTP_500_INTERNAL_SERVER_ERROR
            )









# 3. 处理前端错误调用：/api/resumes/update/ 不带ID的情况
class ResumeUpdateErrorAPIView(APIView):
    """
    处理前端错误调用：当请求 /api/resumes/update/ 不带ID时返回友好错误
    """
    permission_classes = []

    def patch(self, request):
        return Response(
            {
                "error": (
                    "更新请求缺少简历ID。"
                    "请使用正确的路径：/api/resumes/update/<id>/ "
                    "或 /api/resumes/<id>/"
                ),
                "detail": (
                    "URL路径必须包含简历ID，"
                    "例如：/api/resumes/update/3/ 或 /api/resumes/3/"
                )
            },
            status=status.HTTP_400_BAD_REQUEST
        )

    def post(self, request):
        """处理POST请求到 /api/resumes/update/ 不带ID的情况"""
        return self.patch(request)  # 复用相同的错误消息


def audit_resume_payload(instance=None, validated_data=None):
    """
    聚合简历关键字段，调用违规词审核。

    :param instance: PersonalInfo 实例（更新场景下的原始数据）
    :param validated_data: DRF validated_data（创建或更新时的新数据）
    :return: 审核结果字典
    """
    parts = []

    def _stringify(value):
        if value is None:
            return ""
        return str(value)

    def _get_value(field):
        if validated_data and field in validated_data:
            return validated_data[field]
        if instance is not None:
            return getattr(instance, field, "")
        return ""

    # 收集主表字段
    for field in ["name", "graduate_year", "education", "job_status", "phone", "preponderance", "expectedJob"]:
        value = _get_value(field)
        if value:
            parts.append(_stringify(value))

    # 聚合关联经历
    def _collect_nested(key, related_name, fields):
        entries = None
        if validated_data and key in validated_data:
            entries = validated_data[key]
        elif instance is not None:
            entries = getattr(instance, related_name).all()

        if not entries:
            return

        for item in entries:
            if isinstance(item, dict):
                data = item
            else:
                data = {f: getattr(item, f, "") for f in fields}
            for field in fields:
                value = data.get(field)
                if value:
                    parts.append(_stringify(value))

    _collect_nested("work_experiences", "work_experiences", ["company", "position", "description"])
    _collect_nested("project_experiences", "project_experiences", ["project_name", "role", "description"])
    _collect_nested("education_experiences", "education_experiences", ["school", "education", "major", "description"])

    # 拼接为一个字符串提交审核
    content = " ".join(parts)
    auditor = MessageAuditFactory.get_auditor(MessageAuditFactory.RESUME)
    return auditor.audit({"content": content})






